// CountManager.java: Servant Locator for count objects
package Server3;

import org.omg.PortableServer.*;
import org.omg.PortableServer.POAPackage.ObjectNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;

import Server3.CountPOAServant;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Random;
import java.util.Set;
import java.io.*;
import java.util.ArrayList;

public class CountManagerActivator extends ServantActivatorPOA
{
        private final int servantLimit;
        private int activeServants;
        private ArrayList<byte[]> activeIdArray;
        private HashMap<String, Integer> deactivatedServantHash;
        private LinkedList<DeactivatedNode> deactivatedServantList;
       
   
        public CountManagerActivator() {
                servantLimit = 1000;
                activeServants = 0;
                activeIdArray = new ArrayList<byte[]>();
                deactivatedServantHash = new HashMap<String, Integer>(100000);
                deactivatedServantList = new LinkedList<DeactivatedNode>();
               
          //      startFileUpdater();
        }

        public CountManagerActivator(int limit) {
                servantLimit = limit;
                activeServants = 0;
                activeIdArray = new ArrayList<byte[]>();
                deactivatedServantHash = new HashMap<String, Integer>(100000);
                deactivatedServantList = new LinkedList<DeactivatedNode>();
               
         //       startFileUpdater();
        }
       
	private class FileUpdaterThread implements Runnable {
	
	    private HashMap<String, Integer> deactivatedServantHash;
	   
	    public FileUpdaterThread(HashMap<String, Integer> deactivatedServantHash) {
	            this.deactivatedServantHash = deactivatedServantHash;
	    }
	
	    public void run() {
	        for(;;) {
	        	
	        	try {
					Thread.sleep(10);
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
	        	
	        	synchronized(deactivatedServantHash) {
		            if (!deactivatedServantHash.isEmpty()) {
		
		                System.out.println("There are " + deactivatedServantHash.size() + "counters waiting to be saved.");
		                
	//	                DeactivatedNode nodeToWrite = deactivatedServantList.remove();
		                
		                Set<String> objectIDSet = deactivatedServantHash.keySet();
		                String objectIDToSave  = null;
		                for (String x: objectIDSet) {
		                	objectIDToSave = x;
		                	break;
		                }
		                
		                int sum = deactivatedServantHash.get(objectIDToSave);
		                System.out.println(sum + " is being saved.");
		                
	//	                System.out.println(new String(nodeToWrite.objectID) + " with sum of " + nodeToWrite.sum +  " waiting to be saved.");
		               
		                FileOutputStream f_Out = null;
		                try {
		                    f_Out = new FileOutputStream(objectIDToSave+".state");
		                } catch (FileNotFoundException e) {
		                    // TODO Auto-generated catch block
		                    e.printStackTrace();
		                }
		                       
		                PrintWriter b_Out = new PrintWriter(new OutputStreamWriter(f_Out));
		                b_Out.println(sum);
		                b_Out.close();
		                try {
		                    f_Out.close();
		                } catch (IOException e) {
		                        // TODO Auto-generated catch block
		                    e.printStackTrace();
		                }
		                
		                deactivatedServantHash.remove(objectIDToSave);
		            }
	        	}
	        }
	    }
	}
       
        private class DeactivatedNode {
                byte[] objectID;
                int sum;
        }
       
    public Servant incarnate(byte[] objectID, POA poa)
    {

	//              System.out.println(".....incarnate called for object ID "+new String(objectID));
	//              System.out.println(".....creating new servant");
	//              System.out.println(".....activeServants = " + activeServants);
	   
	    if (activeServants < servantLimit) {
	        try
	        {
	            CountPOAServant servant = new CountPOAServant();
	           
	            int sum = 0;
	           
	            synchronized(deactivatedServantHash) {
	            
		            if (!deactivatedServantHash.containsKey(objectID)) {
	                    FileInputStream f_In = new FileInputStream( new String(objectID)+".state");
	                    System.out.println(".....incarnate called for object ID " + new String(objectID));
	                    BufferedReader b_In = new BufferedReader(new InputStreamReader(f_In));
	                    sum = Integer.parseInt(b_In.readLine());
	                    b_In.close();
	                    f_In.close();
		            } else
	                    sum = deactivatedServantHash.get(objectID).intValue();
	            }
	            
	            servant.sum(sum);
	
	                
	            activeIdArray.add(objectID);
	            activeServants++;
	
	            return servant;
	        }
	        catch(Exception E)
	        {
                System.out.println(".....exception encountered during state restore.");
                E.printStackTrace();
                return null;
	        }
	    } else {
	    	Random randomGen = new Random();
	         
			int random = randomGen.nextInt(activeServants);
			byte[] deactivateID = activeIdArray.remove(random);
			Servant servantToDeactivate = null;
	         
	        try {
                servantToDeactivate = poa.id_to_servant(deactivateID);
	        } catch (ObjectNotActive e) {
	                // TODO Auto-generated catch block
                e.printStackTrace();
	        } catch (WrongPolicy e) {
	                // TODO Auto-generated catch block
                e.printStackTrace();
	        }
	         
            System.out.println(".....objectID to etherealize: " + new String(deactivateID));

			etherealize(deactivateID, poa, servantToDeactivate, false, false);
			activeServants--;
			 
			return incarnate(objectID, poa);
	    }
    }

    public void etherealize(byte[] objectID, POA poa, Servant servant, boolean cleanup_in_progress, boolean remaining_activations)
    {
//      System.out.println(".....etherealize called for object ID "+new String(objectID));

        try {
//            DeactivatedNode nodeToDeactivate = new DeactivatedNode();
//            nodeToDeactivate.objectID = objectID;
            int sum = ((CountPOAServant)(servant)).sum();
//            nodeToDeactivate.sum = sum;
            
            System.out.println(sum + " IS GOING TO BE ADDED TO THE QUEUE");
            
            synchronized(deactivatedServantHash) {
            	deactivatedServantHash.put(new String(objectID), Integer.valueOf(sum));
            }
//            deactivatedServantList.add(nodeToDeactivate);
        	
            poa.deactivate_object(objectID);
        }
        catch(Exception E) {
            System.out.println(".....EXCEPTION encountered during state save.");
        }
       
    }

    private void startFileUpdater() {
        FileUpdaterThread myThread = new FileUpdaterThread(deactivatedServantHash);
        new Thread(myThread).start();
    }
}
